package edu.hawaii.halealohacli.command;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.SortedMap;
import java.util.Timer;
import org.wattdepot.client.NotAuthorizedException;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.client.WattDepotClientException;
import org.wattdepot.resource.source.jaxb.Source;
import edu.hawaii.halealohacli.HaleAloha;

/**
 * This command prints out a timestamp, the current power being consumed by the [tower | lounge].
 * Prints out also whether or not the lounge is meeting its power conservation goal.   
 * [goal] is an integer between 1 and 99. It defines the percentage reduction from the baseline.  
 * [interval] is an integer greater than 0.  
 * @author Alex
 *
 */
public class MonitorGoal implements Command {
  SortedMap<String, List<Double>> baseline = HaleAloha.getBaseLine();
  List<Double> list;
  private String source;
  private String output;
  private WattDepotClient client;
  private int interval;
  private int goal;
  private String command = "monitor-goal";
  private String arguments = "[tower | lounge] [interval] [goal]";
  private int numParams = 3;
  private String help = "This command prints out a timestamp, " +
                        "the current power being consumed by the [tower | lounge], " +
                        "and whether or not the lounge is meeting its power conservation goal. " +
                        "[goal] is an integer between 1 and 99. " +
                        "It defines the percentage reduction from the baseline " +
                        "[interval] is an integer greater than 0.";
  
  @Override
  public String run(String[] input, WattDepotClient client) throws Exception {
    //checking the number of inputs
    if (input.length != 4) {
      this.output = "Need 4 arguments: [tower | lounge] [interval] [goal] . Try again.";
      return output;
    }
    //assigning the values
    this.source = input [1];
    String interval = input[2];
    String goal = input[3];
    this.client = client;
    //validate the goal input
    if (!checkGoal (goal)) {
      this.output = "[goal] is an integer between 1 and 99.";
      return output;
    }
    //validate the interval input
    if (!checkInterval (interval)) {
      this.output = " [interval] is an integer greater than 0.";
      return output;
    }
    //Put all sources into an array
    String [] sourceNames = new String [100];
    int i = 0;
    try {
      List<Source> sources;
      sources = client.getSources();
      
      for (Source source : sources) {
        sourceNames[i] = source.getName();
        i++;          
      }
    }
    catch (NotAuthorizedException e) {
      output = "You are not authorized to access this client.";
    }
    catch (WattDepotClientException e) {
      output = "An unexpected error occured. Please try again.";
    }
    
    // Check if source is a valid source by comparing to array of names.
    if (!Arrays.asList(sourceNames).contains(this.source)) {  
      return "\"" + this.source + "\" is not a valid source.";
    }
    //check if there is a baseline for the source input
    if (!this.baseline.containsKey(this.source)) {
      return "There is no baseline for " + this.source + ". " +
          "Please run set-baseline first for the desired tower/lounge.";
    }
    list = this.baseline.get(this.source);
    //Everything looks fine, go ahead and execute
    execute ();
    return "";
  }
    
  /**
   * Validate the goal argument.
   * @param goal the String to validate.
   * @return true if the String is valid; otherwise false.
   */
  public boolean checkGoal (String goal) {
    try {
      this.goal = Integer.parseInt(goal);
    }
    catch (NumberFormatException nfe) {
      return false;
    }
    if (this.goal < 1 || this.goal > 99) {
      return false;
    }
    return true;
  }
  
  /**
   * Validate the interval argument.
   * @param interval the String to validate.
   * @return true if the String is valid; otherwise false.
   */
  public boolean checkInterval (String interval) {
    try {
      this.interval = Integer.parseInt(interval);
    }
    catch (NumberFormatException nfe) {
      return false;
    }
    if (this.interval < 1) {
      return false;
    }
    return true;
  }
  
  /**
   * Get the current time.
   * @return the current time.
   */
  public String getCurrentTime () {
    Calendar calendar = new GregorianCalendar();
    SimpleDateFormat checkTime = new SimpleDateFormat("HH:mm:ss", Locale.US);
    return checkTime.format(calendar.getTime());
  }
  
  /**
   * Prints out the data.
   * @throws Exception exception.
   */
  public void execute () throws Exception {
    //HEADER FORMAT
    System.out.println("Beginning monitoring of " + "\"" + this.source + "\"" + 
        " at " + interval + " second intervals. Press <Enter> to stop");
    System.out.printf("%-10s %-15s %-18s %-14s %-15s %n", 
        "Time", "Power (KW)", "Baseline (KW)", "Goal (KW)", "Goal Success?");
    
    // Create new timer and monitorGoalTask to run.
    Timer timer = new Timer();
    MonitorGoalTask monitorTask = new MonitorGoalTask(source, client, goal, list);
    monitorTask.run();
    
    // Intervals are in milliseconds. Need to multiple by 1000 to get seconds.
    interval *= 1000;
    timer.scheduleAtFixedRate(monitorTask, interval, interval);
    try {
      while (System.in.available() == 0) {      
        Thread.sleep(500);     
      }
    }
    catch (IOException e) {
      System.out.println("Input Error. Please try again.");
    }
    catch (InterruptedException e) {
      System.out.println("Error. Please try again.");
    }    
    timer.cancel();
    output = "Monitoring has ended. Returning to main program.";
  }
  
  @Override
  public String getCommand() {
    return this.command;
  }

  @Override
  public int getNumParams() {
    return this.numParams;
  }

  @Override
  public String getHelp() {
    return this.command + " " + this.arguments + "\n" + this.help;
  }

}
